import crypto from 'crypto'

async function getMasterKey() {
  const k = await redis.get('xiuxian:secret:master')
  if (k) return Buffer.from(k, 'base64')
  const mk = crypto.randomBytes(32)
  await redis.set('xiuxian:secret:master', mk.toString('base64'))
  return mk
}

async function getUserKey(uid) {
  const mk = await getMasterKey()
  const h = crypto.createHmac('sha256', mk).update(String(uid)).digest()
  return h.subarray(0, 32)
}

async function encrypt(uid, obj) {
  const key = await getUserKey(uid)
  const iv = crypto.randomBytes(12)
  const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)
  const plaintext = Buffer.from(JSON.stringify(obj), 'utf8')
  const enc = Buffer.concat([cipher.update(plaintext), cipher.final()])
  const tag = cipher.getAuthTag()
  return {
    alg: 'AES-256-GCM',
    iv: iv.toString('base64'),
    tag: tag.toString('base64'),
    ciphertext: enc.toString('base64')
  }
}

async function decrypt(uid, wrapper) {
  const key = await getUserKey(uid)
  const iv = Buffer.from(wrapper.iv, 'base64')
  const tag = Buffer.from(wrapper.tag, 'base64')
  const ct = Buffer.from(wrapper.ciphertext, 'base64')
  const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
  decipher.setAuthTag(tag)
  const dec = Buffer.concat([decipher.update(ct), decipher.final()])
  return JSON.parse(dec.toString('utf8'))
}

export default { encrypt, decrypt }
